/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package demo.parallelcore;

import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*
 * This class demos find operation that attach to collection, findFirst returns
 * first element in the stream, it's reasonable we can expect it's the first
 * element in the collection if collection is ordered. On the contrary, findAny
 * returns any element in the stream, this is result for parallel computation,
 * we shouldn't have any assumption on the return result.
 * @author tyan
 */

public class Elements  extends DemoHelper {
    /*
     * Find any supplier or first supplier in country, this demos how implement a 
     * simple find on a source with one condition 
     *
     * @param   findAny true  perform findAny on stream
     *                false perform findFirst on stream
     * @param   country supplier's country
     * @return  any/first supplier in given country
    */
    public static Optional<Supplier> suppliersInCountry(boolean findAny,
            String country) {
        //A function that find any/first supplier from a supplier Stream
        Function<Stream<Supplier>, Optional<Supplier>> findInStream 
                = findAny ? Stream<Supplier>::findAny : 
                            Stream<Supplier>::findFirst;
        return findInStream.
                //find any/first supplier
                apply(suppliers.parallelStream().
                //filter supplier who is same sa given country
                filter(supplier -> country.
                        equals(supplier.getCountry())));
    } 
    
    /*
     * Get mapping table between category to any/first in-stock product.
     * @param   findAny true  perform findAny on stream
     *                false perform findFirst on stream
     * @return  a map mapping every category to any/first in-stock product
    */
    public static Map<String, Product> inStockProductsByCategory(
            boolean findAny) {
        //Customized collector to filter In-Stock supplier
        Collector<Product, ?, Product> findInStock = 
                //supplier for generate a ArrayList
                Collector.of(ArrayList<Product>::new,
                //accumulator for only add in-stock product
                (list, p) -> { if(p.getUnitsInStock() > 0) list.add(p); }, 
                (left, right) -> { left.addAll(right); return left; },
                //combiner that get any/first product, return null if there is
                //not any
                l -> findAny ? l.parallelStream().findAny().orElse(null) : 
                        l.parallelStream().findFirst().orElse(null));
        return products.parallelStream().
                //Grouping product into a map which key is category, value is
                //any/first in-stock product in this category
                collect(Collectors.groupingBy(Product::getCategory, 
                        findInStock));
    }
}
